Popular Searches
Popular Course Categories
Popular Courses

Managing Configuration Changes and Screen State Restoration

Managing Configuration Changes and Screen State Restoration

Android Architecture and State Management

Managing Configuration Changes and Screen State Restoration

Course: Android App Development

Topic: Managing Configuration Changes and Screen State Restoration

Course Link: Android App Development Course

Demo Link: Register for a Free Demo

Website: JustAcademy Official Website


1. Introduction

Android applications run on devices with different screen sizes, orientations, languages, themes, and hardware configurations. During the application's lifetime, these configurations can change because the user rotates the device, switches to dark mode, resizes a window, changes the system language, or connects an external keyboard.

Some configuration changes cause Android to destroy and recreate the current Activity. When this happens, values stored only in the Activity's instance variables can be lost. For example, a user may be filling out a registration form, writing a message, or searching for a product when the screen rotates. Without proper state management, the entered information may disappear.

Configuration change management means ensuring that the application adapts correctly to a changed device configuration. Screen state restoration means recovering the relevant UI state after an Activity, Fragment, or application process is recreated.

2. Learning Objectives

  • Understand Android configuration changes and Activity recreation.
  • Identify different types of UI state and application data.
  • Understand Activity lifecycle callbacks during configuration changes.
  • Use onSaveInstanceState() and saved instance state Bundles.
  • Preserve screen state using ViewModel and SavedStateHandle.
  • Restore user input and UI state in Jetpack Compose.
  • Distinguish configuration changes from process death.
  • Implement reliable state restoration using Kotlin.
  • Test state restoration and troubleshoot common problems.

3. What Are Configuration Changes?

A configuration change occurs when an environmental property affecting the application changes while it is running. Android provides configuration information through resources and system APIs so that the application can adjust its UI and behavior accordingly.

Common configuration changes

Configuration Change Example Possible Effect
Orientation Portrait changes to landscape Activity recreation and layout changes
Screen size App window is resized Different layout arrangements may be required
Window size class Foldable device is unfolded UI may need to display additional content
Dark or light theme User changes system theme Colors and theme resources may change
Language or locale User changes the device language Localized text and formatting may change
Font scale User increases text size Text wrapping and layout dimensions may change
Keyboard availability Physical keyboard connects Input and layout behavior may change
Display density App moves to a display with different density Resources and dimensions may change

Android does not necessarily recreate an Activity for every environmental change. The exact behavior depends on the change, the Android version, the app's configuration, and the APIs involved. Applications should be designed to handle relevant changes without losing important state.

4. Why Does Android Recreate an Activity?

Android uses Activity recreation to reload resources and allow an application to rebuild its interface for the new configuration. For example, an application may provide separate layouts for portrait and landscape orientation.

When the Activity is recreated, Android creates a new Activity instance. The old instance's ordinary instance variables do not automatically transfer to the new instance. Therefore, state must be retained or restored through an appropriate mechanism.

Example of state loss

class MainActivity : AppCompatActivity() {
    private var userName = ""

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

In this example, userName is stored in the Activity instance. If the Activity is destroyed and recreated, the new instance initializes userName to an empty string. Unless the value is restored from another source, the previous value is lost.

5. Understanding Activity Lifecycle During Recreation

Activity lifecycle callbacks help developers understand when the current screen is created, stopped, destroyed, and recreated.

Typical sequence

  1. onPause(): The Activity loses its fully active state.
  2. onSaveInstanceState(): Android may request a saved instance state snapshot before the Activity is destroyed.
  3. onStop(): The Activity is no longer visible.
  4. onDestroy(): The old Activity instance is destroyed.
  5. onCreate(): A new Activity instance is created, potentially receiving the saved Bundle.
  6. onStart(): The new Activity becomes visible.
  7. onResume(): The Activity returns to the foreground and becomes interactive.

This is a typical sequence, not a guarantee that every callback occurs in precisely this order for every lifecycle scenario. Saved-state timing and callbacks depend on the situation. State-saving code should not depend on receiving a callback that Android does not guarantee.

6. Types of State in Android Applications

Choosing the right restoration strategy starts with identifying what kind of information needs to survive.

6.1 UI State

UI state describes the current appearance and interaction state of a screen.

  • Text entered in a search field.
  • Selected tab or filter.
  • Current scroll position.
  • Expanded or collapsed sections.
  • Selected item in a list.
  • Current navigation destination.

6.2 Screen or Business State

This state represents information required by the screen's logic, such as a selected product ID, a search query, loading status, or the data needed to rebuild a result screen.

6.3 Persistent Application Data

This includes information that must remain available beyond Activity recreation or process death, such as saved notes, user preferences, offline records, and completed transactions. Databases, DataStore, or appropriate server-side storage are generally better suited for durable data.

7. Methods for Managing Configuration Changes

Method Primary Purpose Survives Configuration Change Survives System Process Death
ViewModel Retain in-memory screen data Yes No, not by itself
onSaveInstanceState() Save a small state snapshot Yes Usually, when Android saved and restores the state
SavedStateHandle Retain small ViewModel state for restoration Yes Supports system restoration
rememberSaveable Save small Compose UI state Yes Supports system restoration
Room database Persist structured application data Yes Yes
DataStore Persist preferences and small settings Yes Yes

Saved-state mechanisms have size and serialization limitations. They are intended for small amounts of information needed to reconstruct a screen, not large bitmaps, large result lists, or complete database records.

8. Using onSaveInstanceState() to Save Screen State

The onSaveInstanceState() callback allows an Activity to place a small amount of state into a Bundle. Android can supply that Bundle to the recreated Activity through onCreate() or onRestoreInstanceState().

Example: Saving a user's name

class MainActivity : AppCompatActivity() {

    private var userName: String = ""

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        userName = savedInstanceState?.getString("USER_NAME") ?: ""

        val nameInput = findViewById<EditText>(R.id.nameInput)
        nameInput.setText(userName)
    }

    override fun onSaveInstanceState(outState: Bundle) {
        outState.putString("USER_NAME", userName)
        super.onSaveInstanceState(outState)
    }
}

In this example, the application saves the name under the USER_NAME key and retrieves it when the Activity is recreated. In a real form, update userName whenever the user changes the text, or read the current text from the EditText when saving.

Reading the value directly from the input field

override fun onSaveInstanceState(outState: Bundle) {
    val nameInput = findViewById<EditText>(R.id.nameInput)

    outState.putString(
        "USER_NAME",
        nameInput.text.toString()
    )

    super.onSaveInstanceState(outState)
}

Important points

  • Use stable keys to identify saved values.
  • Restore values before or while binding the UI.
  • Save only small, necessary values.
  • Do not assume saved state is always available; the Bundle may be null on a fresh launch.
  • Do not rely on onSaveInstanceState() as a guaranteed final save for every way an app can terminate.

9. Restoring State with onRestoreInstanceState()

Android may invoke onRestoreInstanceState() after onStart() when saved state is available. It provides another place to restore saved values after the Activity has been created.

class ProfileActivity : AppCompatActivity() {

    private var selectedTab = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_profile)
    }

    override fun onSaveInstanceState(outState: Bundle) {
        outState.putInt("SELECTED_TAB", selectedTab)
        super.onSaveInstanceState(outState)
    }

    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
        super.onRestoreInstanceState(savedInstanceState)

        selectedTab = savedInstanceState.getInt("SELECTED_TAB", 0)
        // Update the selected tab in the UI here.
    }
}

Use either onCreate() or onRestoreInstanceState() according to your initialization needs. Restoring in onCreate() is useful when the state must be available during initial UI setup. The Bundle can be null in onCreate() when no saved state exists.

10. Managing State with ViewModel

A ViewModel stores UI-related data separately from an Activity or Fragment. The same ViewModel instance normally survives configuration-driven Activity recreation, allowing screen data to remain available without being saved and reloaded for every rotation.

A ViewModel does not, by itself, survive system-initiated process death. For that scenario, combine it with SavedStateHandle or load durable information from persistent storage.

Example: ViewModel for a search screen

class SearchViewModel : ViewModel() {

    var searchQuery: String = ""
        private set

    fun updateQuery(query: String) {
        searchQuery = query
    }
}

An Activity can obtain the ViewModel through the AndroidX ViewModel APIs:

class SearchActivity : AppCompatActivity() {

    private val viewModel: SearchViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_search)

        val searchInput = findViewById<EditText>(R.id.searchInput)
        searchInput.setText(viewModel.searchQuery)

        searchInput.doAfterTextChanged { text ->
            viewModel.updateQuery(text?.toString().orEmpty())
        }
    }
}

This example uses the AndroidX KTX extension doAfterTextChanged, which requires the appropriate AndroidX dependency. The ViewModel preserves the query through ordinary configuration changes. Use SavedStateHandle if the query must also be restored after system-initiated process death.

11. Using SavedStateHandle in a ViewModel

SavedStateHandle provides access to saved state inside a ViewModel. It is useful when screen state participates in business logic and must be restored after the system recreates the process and screen.

Example

class SearchViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    companion object {
        private const val KEY_QUERY = "search_query"
    }

    val searchQuery: String
        get() = savedStateHandle[KEY_QUERY] ?: ""

    fun updateQuery(query: String) {
        savedStateHandle[KEY_QUERY] = query
    }
}

When using a standard ViewModel factory or supported AndroidX integration, SavedStateHandle can be provided automatically. If creating ViewModels manually, configure the required factory and saved-state owner correctly.

Why SavedStateHandle is useful

  • It keeps small screen state near the ViewModel that uses it.
  • It survives normal configuration changes through the ViewModel.
  • It can restore saved values after system-initiated process recreation.
  • It helps rebuild a screen using a query, selected item ID, or navigation argument.

12. Handling Configuration Changes in Jetpack Compose

Jetpack Compose uses state-driven UI. When a composable reads state and that state changes, Compose can recompose the relevant UI. However, ordinary remember state is not designed to survive every Activity recreation or process death.

Using rememberSaveable

@Composable
fun NameScreen() {
    var name by rememberSaveable {
        mutableStateOf("")
    }

    Column {
        OutlinedTextField(
            value = name,
            onValueChange = { name = it },
            label = { Text("Enter your name") }
        )

        Text(text = "Hello, $name")
    }
}

rememberSaveable preserves supported small UI state through configuration changes and can participate in system-initiated state restoration. For custom objects, use an appropriate Saver or a supported serialization mechanism. Do not put large objects into saved UI state.

remember and rememberSaveable comparison

Feature remember rememberSaveable
Retains state during recomposition Yes Yes
Designed to survive Activity recreation No Yes
Can restore small saved state after system process death No Yes, when restoration state is available
Best use Temporary composition state Small user-facing UI state

13. Handling Configuration Changes with View Binding

In View-based applications, the layout can be recreated when configuration changes occur. Views from the old Activity instance must not be reused in the new instance.

  • Inflate or bind the new layout in the recreated Activity.
  • Keep reusable screen data in a ViewModel.
  • Restore lightweight transient state using saved-state APIs.
  • Re-observe LiveData or Flow using lifecycle-aware collection.
  • Release references to old Views when the lifecycle owner is destroyed.

Fragments and their view lifecycles also require care. A Fragment can remain alive while its view is destroyed and recreated. Observe view-related data with viewLifecycleOwner and clear view binding references in onDestroyView() when appropriate.

14. Adapting the UI to New Configurations

Preserving state is only one part of configuration handling. The application must also present an appropriate interface for the new environment.

Recommended practices

  • Use resource-qualified layouts and values where appropriate, such as layout-land or values-night.
  • Prefer responsive layouts over hardcoded screen dimensions.
  • Use dp for layout dimensions and sp for text sizes in View-based layouts.
  • Support window resizing and multi-window operation.
  • Use accessible layouts that accommodate larger fonts and different languages.
  • Ensure theme changes update colors, icons, and other themed resources correctly.
  • Keep business logic independent of a particular Activity instance.

15. Should You Override Configuration Handling?

Android provides mechanisms such as android:configChanges for selected configuration changes. These can prevent an Activity from being recreated for specified changes, allowing the Activity to receive onConfigurationChanged() instead.

This is not the default recommendation for ordinary applications. Overriding the standard recreation behavior can make it harder to refresh resources and correctly adapt the UI. Use it only when there is a clear technical reason and the application explicitly handles every relevant configuration update.

For most applications, the better approach is to support Activity recreation correctly, retain screen data in a ViewModel, restore small transient values through saved state, and reload persistent data from its source.

16. Configuration Changes vs. Process Death

Aspect Configuration Change System-Initiated Process Death
Example Rotating the screen Android terminates a background process to reclaim resources
Activity instance Usually recreated for relevant changes Recreated when the user returns to the app
ViewModel Normally retained for the same logical owner Destroyed with the process
Saved state Can restore transient UI values Can restore values if Android previously captured and supplies saved state
Database or durable storage Remains available Remains available

Saved instance state is not a substitute for persistent storage. It is intended to restore the user's immediate context when Android recreates a screen. Data that must remain safe across app restarts, explicit dismissal, or device restarts should be persisted appropriately.

17. Complete Example: Restoring a Search Screen

The following example combines SavedStateHandle with a simple search screen. It demonstrates how to retain the search query and rebuild the screen after recreation. In a production app, the ViewModel would typically expose observable state and perform repository-backed searches.

ViewModel

class ProductSearchViewModel(
    private val state: SavedStateHandle
) : ViewModel() {

    companion object {
        private const val QUERY_KEY = "product_query"
    }

    val query: String
        get() = state[QUERY_KEY] ?: ""

    fun onQueryChanged(value: String) {
        state[QUERY_KEY] = value
    }
}

Activity

class ProductSearchActivity : AppCompatActivity() {

    private val viewModel: ProductSearchViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_product_search)

        val searchInput =
            findViewById<EditText>(R.id.searchInput)

        searchInput.setText(viewModel.query)

        searchInput.doAfterTextChanged { editable ->
            viewModel.onQueryChanged(
                editable?.toString().orEmpty()
            )
        }
    }
}

How the example works

  1. The user types a product search query.
  2. The text listener sends the latest value to the ViewModel.
  3. The ViewModel stores the query in SavedStateHandle.
  4. During an ordinary configuration change, the ViewModel remains available.
  5. If Android later restores the Activity after system-initiated process death, the saved query can be restored when saved state is available.
  6. The Activity repopulates the input field using the stored query.

Note: This example restores the query, not the search results themselves. The application should execute the search again or load the appropriate cached or persistent data. Avoid triggering unnecessary duplicate requests when restoring the screen.

18. Common Problems and Troubleshooting

Problem Possible Cause Solution
Text disappears after rotation Text exists only in a normal Activity variable Use ViewModel, saved state, or supported view-state restoration
Compose text resets State uses remember instead of rememberSaveable Use rememberSaveable for small restorable UI values
ViewModel data disappears after process death ViewModel only retains in-memory data Use SavedStateHandle and/or persistent storage
Search executes repeatedly Search logic runs unconditionally during UI creation Separate state restoration from search execution and use appropriate Flow or lifecycle patterns
Old Views cause crashes References point to a destroyed Activity or Fragment view Rebind views and clear obsolete references
Large saved Bundle causes delays Complex objects or large data are serialized Save IDs or small values and reload large data from storage
Dark mode does not update correctly UI assumes the old configuration remains valid Use theme-aware resources and support configuration recreation
Restoration returns a default value Wrong Bundle key or missing state initialization Check key consistency and distinguish a fresh launch from restored state

19. Best Practices

  • Separate UI from business logic: Avoid storing important application state only in Activity fields.
  • Use ViewModel for active screen state: Retain data across normal configuration changes.
  • Use saved-state APIs for lightweight state: Store queries, IDs, selections, and other small values needed to rebuild the screen.
  • Persist durable data: Use Room, DataStore, files, or an appropriate backend for information that must survive beyond the current screen.
  • Restore the minimum required state: Reconstruct complex objects from stable identifiers instead of serializing entire objects.
  • Make UI rendering repeatable: Recreating a screen should not accidentally submit forms, duplicate payments, or repeat other one-time actions.
  • Handle asynchronous work safely: Use lifecycle-aware observation and cancellation where appropriate.
  • Test multiple configurations: Include rotation, resizing, font scaling, theme changes, and language changes.
  • Respect system behavior: Do not disable configuration recreation merely to avoid implementing state restoration.
  • Protect sensitive data: Do not place passwords, authentication secrets, or unnecessary personal information in saved UI state.

20. Practical Exercises

Exercise 1: Restore a Registration Form

Create a registration screen with name, email, and phone number fields. Rotate the device and ensure the user's unfinished input is preserved. Use appropriate saved-state mechanisms and avoid persisting unnecessary sensitive information.

Exercise 2: Build a Search Screen

Create a search screen using a ViewModel and SavedStateHandle. Preserve the search query and restore the screen after configuration changes. Ensure that results can be reloaded without unnecessary duplicate network requests.

Exercise 3: Compose State Restoration

Create a Jetpack Compose screen containing a text field, selected filter, and expanded section. Use rememberSaveable for the small state values and test the screen after rotating the device.

Exercise 4: Responsive Layout

Create portrait and landscape layouts, or use a responsive layout that adapts to the available width. Verify that the same screen data remains available after the layout changes.

Mini Project: Restorable Notes Application

  • Create a screen to write and edit notes.
  • Use a ViewModel to manage the currently edited note.
  • Use saved state to retain the current note ID and editing context.
  • Use Room or another persistent store to save actual note content.
  • Restore the editor after rotation and system-initiated process recreation.
  • Test that saved notes remain available after closing and reopening the application.

21. Interview Questions and Answers

Q1. What is a configuration change in Android?

Answer: It is a change in device or application environment, such as orientation, screen size, theme, or locale, that may require the application to update its resources or recreate its Activity.

Q2. Why does Android recreate an Activity?

Answer: Android may recreate the Activity to apply resources and configuration appropriate for the new environment. This also gives the application an opportunity to rebuild its UI for the changed configuration.

Q3. What is onSaveInstanceState() used for?

Answer: It saves a small amount of transient UI state into a Bundle so Android can restore that state if it recreates the Activity.

Q4. What is the difference between ViewModel and SavedStateHandle?

Answer: ViewModel retains screen data in memory across configuration changes. SavedStateHandle stores small state values that can be restored after system-initiated process recreation when saved state is available.

Q5. Does a ViewModel survive process death?

Answer: No. The ViewModel is destroyed with the application process. Use SavedStateHandle for small restorable state and persistent storage for durable application data.

Q6. What is the purpose of rememberSaveable?

Answer: It preserves supported small Compose UI state through recomposition, configuration changes, and eligible system-initiated state restoration.

Q7. Should large objects be stored in a saved-state Bundle?

Answer: No. Save a small identifier or the minimum required information, then reload complex data from a database, repository, or other durable source.

Q8. What is the difference between configuration change and process death?

Answer: A configuration change may recreate an Activity while preserving its ViewModel. Process death terminates the application process and destroys its in-memory objects, so restoration requires saved state or persistent storage.

Q9. Why should developers avoid unnecessarily handling configuration changes manually?

Answer: Manual handling increases complexity and requires the app to update resources, layouts, and other configuration-dependent behavior itself. Default Activity recreation is usually simpler and safer when state is managed properly.

Q10. How can configuration changes be tested?

Answer: Rotate the device, resize the app window, change theme and font scale, change locale, and test system-initiated process recreation. Verify that both UI adaptation and relevant user state are correct.

22. Quick Revision Checklist

  • Understand why Android recreates Activities.
  • Identify which values are transient UI state and which are durable application data.
  • Use ViewModel to retain active screen data across configuration changes.
  • Use onSaveInstanceState() for small, restorable Activity state when appropriate.
  • Use SavedStateHandle for small ViewModel state that must be restored after system process recreation.
  • Use rememberSaveable for supported Compose UI state.
  • Store durable application data in persistent storage.
  • Adapt layouts and resources to the new configuration.
  • Test rotation, resizing, process death, and other relevant changes.

23. Conclusion

Managing configuration changes and screen state restoration is essential for building reliable Android applications. Android may recreate Activities when the device configuration changes, and the system may terminate background processes when resources are needed. Applications should therefore separate screen state from Activity instances and choose the correct restoration mechanism for each type of information.

Use ViewModel for in-memory UI data, saved-state APIs for small values needed to reconstruct a screen, and persistent storage for durable application data. In Jetpack Compose, use rememberSaveable for suitable UI state. With these practices, users can rotate their devices, resize application windows, and return to interrupted screens without unnecessarily losing their progress.


Additional Learning Resources

Explore Android App Development with JustAcademy

Build your Android development skills through structured learning and practical projects.

Explore the Android App Development Course

Register for a Course Demo

Visit JustAcademy

Previous Next
whatsapp